package com.ruoyi.collection.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.bizsys.domain.LoanIou;
import com.ruoyi.bizsys.domain.ProductDeferredInfo;
import com.ruoyi.bizsys.domain.ProductInfo;
import com.ruoyi.bizsys.mapper.*;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.Func;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.*;

/**
 *
 * getLoanIouDefferreds 计算用
 *
 * getSelectDefferreds 页面展示用
 * 处理延期还款相关
 */
@Slf4j
@Component
public class ProcessForIouDefferredService {
    @Resource
    LoanIouMapper loanIouMapper;
    @Autowired
    LoanIouDeferredMapper loanIouDeferredMapper;

    @Autowired
    ProductInfoMapper productInfoMapper;
    @Autowired
    LoanOrderMapper loanOrderMapper;
    @Autowired
    ProductDeferredInfoMapper deferredInfoMapper;
    @Autowired
    ProductRelationDeferredMapper productRelationDeferredMapper;

    public static final DecimalFormat currency = new DecimalFormat("#0.00");
//    @PostConstruct
//    public void test() throws ParseException {
//        getSelectDefferreds("1005jju");
//        getSelectDefferreds("1005jju");
//        getSelectDefferreds("1005jju");
//        getSelectDefferreds("1005jju");
//        getSelectDefferreds("1005jju");
//        getSelectDefferreds("1005jju");
//    }

    /**
     * 获取前端展示的延期金融包数据
     * 是否置灰锁，true是needLocked前端
     * msgIndex消息下标
     * 0 ：xx等级的用户可以使用延期还款，请保持良好的还款记录，提升自己等级，解锁延期还款功能。点击确认（如图4-1），关闭弹框，停留在当前页面；
     * 1：弹框提示：请按期还款，保持良好的还款记录，解锁延期还款功能
     * @param loanSerialNo
     * @return
     * @throws ParseException
     */
    public List<ProductDeferredInfo> getSelectDefferreds(String loanSerialNo) throws ParseException {
        LoanIou loanIou = getLoanIou(loanSerialNo);
        if (loanIou == null) return null;
        ProductInfo productInfo = getProductId(loanIou);
        List<ProductDeferredInfo> productDeferredInfoList = null;
        // 未使用延期包
        if (0 == loanIou.getIsDeferred()) {
            //未使用延期包
            log.info("getLoanIouDefferred {}:未使用延期包", loanSerialNo);
            // iou剩余本金
            BigDecimal principal = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal());
            // 查询借据支持的延期金融包,代入借据的数据
            productDeferredInfoList = deferredInfoMapper.getProductDerferedsForShow(
                            productInfo.getId(),
                            principal,
                            loanIou.getPeriodNum(),
                            productInfo.getDeferredMaxDays()
                    );
            if (CollectionUtils.isEmpty(productDeferredInfoList)) {
                log.info("getLoanIouDefferred {}:对应的产品{},没有延期包", loanSerialNo, productInfo.getId());
                return null;
            }
            for (int i = 0; i < productDeferredInfoList.size(); i++) {
                ProductDeferredInfo productDeferredInfo = productDeferredInfoList.get(i);
                checkNeedLock(loanIou, productDeferredInfo);
            }
        }else{
            //用户存在子借据
            productDeferredInfoList = doUserHasDeferd(loanIou, productInfo);
        }
        return productDeferredInfoList;

    }

    /**
     * 查询借据
     * @param loanSerialNo
     * @return
     */
    private LoanIou getLoanIou(String loanSerialNo) {
        LoanIou loanIou = loanIouMapper.getLoanIouByLoanSerialNo(loanSerialNo);
        if (null == loanIou) {
            log.info("getLoanIouDefferred {}:借据不存在{}", loanSerialNo);
            return null;
        }
        if (checkIouStatus(loanIou)) {
            log.info("getLoanIouDefferred {}:借据状态不匹配", loanSerialNo);
            return null;
        }
        return loanIou;
    }

    /**
     * 用户存在子借据 需要计算期数使用和最大天数使用
     * @param loanIou
     * @param productInfo
     * @return
     */
    private List<ProductDeferredInfo> doUserHasDeferd(LoanIou loanIou, ProductInfo productInfo) throws ParseException {
        if (checkMaxDerferDay(loanIou, productInfo)) return null;
        // iou剩余本金
        BigDecimal principal = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal());
        // 查询借据支持的延期金融包,代入借据的数据getPeriodNum需要加上延期的天数进行计算
        List<ProductDeferredInfo> productDeferredInfoList =deferredInfoMapper.getProductDerferedsForShow(
                productInfo.getId(),
                principal,
                loanIou.getDeferredPeriodNum(),//此处是加上了延期的天数
                productInfo.getDeferredMaxDays()
        );
        if (CollectionUtils.isEmpty(productDeferredInfoList)) {
            log.info("getLoanIouDefferred {}:对应的产品{},无有效的延期包", loanIou.getLoanSerialNo(), productInfo.getId());
            return null;
        }
        doProductDeferredInfoListForUserShow(loanIou, productDeferredInfoList);
        return productDeferredInfoList;
    }

    /**
     * 用户存在子借据需要展示给前端的，存在规则，不能过滤时间和激活未激活
     * @param loanIou
     * @param productDeferredInfoList
     */
    private void doProductDeferredInfoListForUserShow(LoanIou loanIou, List<ProductDeferredInfo> productDeferredInfoList) {
        // 获取已经使用的延期包
        List<Long> iouDeferreds = loanIouDeferredMapper.getProductDeferredIds(loanIou.getLoanSerialNo());
        // 循环判断延期产品的期数
        for (int i = 0; i < productDeferredInfoList.size(); i++) {
            ProductDeferredInfo productDeferredInfo = productDeferredInfoList.get(i);
            // 延期期数
            int numDeferredTimes = productDeferredInfo.getNumDeferredTimes();
            long id = productDeferredInfo.getId();
            // 获取用户已经使用的当前i的延期id的次数
            int hasCount = Collections.frequency(iouDeferreds, id);
            if (hasCount >= numDeferredTimes) {
                // 使用完了次数
                productDeferredInfoList.remove(i);
                continue;
            }
            checkNeedLock(loanIou, productDeferredInfo);
        }
    }

    private void checkNeedLock(LoanIou loanIou, ProductDeferredInfo productDeferredInfo) {
        // 前端是否上置灰锁
        // 金融产品绑定的延期产品未激活
        if(productDeferredInfo.getShowIsActive()==0){
            productDeferredInfo.setNeedLocked(true);
            productDeferredInfo.setMsgIndex(0);
            return;
        }
        // 用户逾期还款，且超过延期保留时间
        // 保留天数
        int numDeferredRetainDay = productDeferredInfo.getNumDeferredRetainDay();
        String repayDate = loanIou.getRepayDate();
        if(loanIou.getIsDeferred()==1){
            repayDate = loanIou.getDeferredRepayDate();
        }
        if(checkUserDeferredRetainDay(repayDate,numDeferredRetainDay)){
            log.info("不在保留天数内：false");
            productDeferredInfo.setNeedLocked(true);
            productDeferredInfo.setMsgIndex(1);
            return;
        }
    }

    /**
     * 判断用户 用户当前日期>借据到期日期（天）+延期保留时间（天）
     * @param deferredRepayDate
     * @param numDeferredRetainDay
     * @return
     */
    private boolean checkUserDeferredRetainDay(String deferredRepayDate, int numDeferredRetainDay) {
        Date repayDay = DateUtils.parseDate(deferredRepayDate);
        long a = DateUtils.getDatePoorDay(new Date(),repayDay);
        if(a>numDeferredRetainDay){
            log.info("不在保留天数内：false");
            return true;
        }
        log.info("在保留天数内：true");
        return false;
    }

//    public static void main(String[] args) {
//        int numDeferredRetainDay = 3;
//        Date repayDay = DateUtils.parseDate("2022/06/06");
//        long a = DateUtils.getDatePoorDay(new Date(),repayDay);
//        if(a<=numDeferredRetainDay){
//            System.out.println(true);
//        }else{
//            System.out.println(false);
//        }
//
//
//    }

    /**
     * 检查是否小于最大延期天数
     * @param loanIou
     * @param productInfo
     * @return
     */
    private boolean checkMaxDerferDay(LoanIou loanIou, ProductInfo productInfo) {
        //使用了延期包
        log.info("getLoanIouDefferred {}:使用了延期包", loanIou.getLoanSerialNo());
        //总天数
        int deferredMaxDays = productInfo.getDeferredMaxDays();
        //延期天数
        int deferredPeriodNum = loanIou.getDeferredPeriodNum();

        int leftDays = deferredMaxDays - deferredPeriodNum;
        log.info("getLoanIouDefferred {},剩余延期天数{}", loanIou.getLoanSerialNo(), leftDays);
        if (leftDays < 0) {
            log.info("getLoanIouDefferred {}:延期最大天数{}不足", loanIou.getLoanSerialNo(), deferredMaxDays);
            return true;
        }
        return false;
    }


    /**
     * 判断用户借据是否支持延期包，返回支持的列表(激活的)
     * @param loanSerialNo
     */
    public List<ProductDeferredInfo> getLoanIouDefferreds(String loanSerialNo) throws ParseException {
        LoanIou loanIou = getLoanIou(loanSerialNo);
        if (loanIou == null) return null;
        ProductInfo productInfo = getProductId(loanIou);
        // 未使用延期包
        if (0 == loanIou.getIsDeferred()) {
            //未使用延期包
            log.info("getLoanIouDefferred {}:未使用延期包", loanSerialNo);
            // iou剩余本金
            BigDecimal principal = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal());
            Date repayDate = DateUtils.parseDate(loanIou.getRepayDate(), DateUtils.YYYY_MM_DD_SLASH);
            // 查询借据支持的延期金融包,代入借据的数据
            List<ProductDeferredInfo> productDeferredInfoList =
                    deferredInfoMapper.getProductDerfereds(
                            productInfo.getId(),
                            principal,
                            DateUtils.parseDateToStr("yyyy-MM-dd 23:59:59", repayDate),
                            loanIou.getPeriodNum(),
                            productInfo.getDeferredMaxDays()
                    );
            if (CollectionUtils.isEmpty(productDeferredInfoList)) {
                log.info("getLoanIouDefferred {}:对应的产品{},没有延期包", loanSerialNo, productInfo.getId());
                return null;
            }
            return productDeferredInfoList;
        }
        return getHasDerferreds(loanIou, productInfo);
    }

    /**
     * 使用了延期包的计算
     * @param loanIou
     * @param productInfo
     * @return
     */
    private List<ProductDeferredInfo> getHasDerferreds(LoanIou loanIou, ProductInfo productInfo) throws ParseException {
        if (checkMaxDerferDay(loanIou, productInfo)) return null;
        // iou剩余本金
        BigDecimal principal = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal());
        Date repayDate = DateUtils.parseDate(loanIou.getDeferredRepayDate(), DateUtils.YYYY_MM_DD_SLASH);
        // 查询借据支持的延期金融包,代入借据的数据getPeriodNum需要加上延期的天数进行计算
        List<ProductDeferredInfo> productDeferredInfoList =
                deferredInfoMapper.getProductDerfereds(
                        productInfo.getId(),
                        principal,
                        DateUtils.parseDateToStr("yyyy-MM-dd 23:59:59", repayDate),//此处是延期的repaydate
                        loanIou.getDeferredPeriodNum(),//此处是加上了延期的天数
                        productInfo.getDeferredMaxDays()
                );
        if (CollectionUtils.isEmpty(productDeferredInfoList)) {
            log.info("getLoanIouDefferred {}:对应的产品{},无有效的延期包", loanIou.getLoanSerialNo(), productInfo.getId());
            return null;
        }
        doProductDeferredInfoList(loanIou, productDeferredInfoList);
        return productDeferredInfoList;
    }

    private void doProductDeferredInfoList(LoanIou loanIou, List<ProductDeferredInfo> productDeferredInfoList) {
        // 获取已经使用的延期包
        List<Long> iouDeferreds = loanIouDeferredMapper.getProductDeferredIds(loanIou.getLoanSerialNo());
        // 循环判断延期产品的期数
        for (int i = 0; i < productDeferredInfoList.size(); i++) {
            ProductDeferredInfo productDeferredInfo = productDeferredInfoList.get(i);
            // 延期期数
            int numDeferredTimes = productDeferredInfo.getNumDeferredTimes();
            // 延期天数
            int numDeferredDay = productDeferredInfo.getNumDeferredDay();
            long id = productDeferredInfo.getId();
            // 获取用户已经使用的当前i的延期id的次数
            int hasCount = Collections.frequency(iouDeferreds, id);
            if (hasCount >= numDeferredTimes) {
                // 使用完了次数
                productDeferredInfoList.remove(i);
            }
        }
    }

    public ProductInfo getProductId(LoanIou loanIou) {
        //获取productId，loanIou遗留问题导致没有，需要loan_order中获取fkProductId
        if (null != loanIou.getProductId()) {
            return productInfoMapper.selectById(loanIou.getProductId());
        }
        long productId = loanOrderMapper.getProductIdByloanSerialNo(loanIou.getLoanSerialNo());
        loanIou.setProductId(productId);
        loanIouMapper.updateById(loanIou);
        return productInfoMapper.selectById(productId);
    }

    /**
     * 等待还款和逾期才能继续
     *
     * @param loanIou
     * @return true 可以继续
     */
    private boolean checkIouStatus(LoanIou loanIou) {
        if (LoanIou.LOAN_IOU_STATUS_SETTLE == loanIou.getIouStatus()) {
            return true;
        }
        return false;
    }

//    @PostConstruct
//    public void test(){
//        JSONObject params = new JSONObject();
//        params.put("loanSerialNo","1005jju");
//        params.put("deferredId","1");
//        getTotalAmountBy(params);
//    }




    /**
     * 获取延期的还款试算
     * @param params
     * @return
     */
    public BigDecimal getTotalAmountBy(JSONObject params){
        log.info("延期产品还款试算：{}",params.toJSONString());
        String loanSerialNo = params.getString("loanSerialNo");
        int deferredId = params.getIntValue("deferredId");
        LoanIou loanIou = loanIouMapper.getLoanIouByLoanSerialNo(loanSerialNo);
        if (null == loanIou) {
            log.info("获取延期的还款试算 {}:借据不存在{}", loanSerialNo);
            return BigDecimal.ZERO;
        }
        // check deferredId 是否有效
        ProductDeferredInfo productDeferredInfo = checkUserSelectDeferredId(loanIou,deferredId);
        return getMinPay(loanIou, productDeferredInfo);
    }

    /**
     * 计算 getMinPay
     * @param loanIou
     * @param productDeferredInfo
     * @return
     */
    public BigDecimal getMinPay(LoanIou loanIou, ProductDeferredInfo productDeferredInfo) {
        BigDecimal toBeRepaid = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal());
        BigDecimal deferredInterest = BigDecimal.ZERO;
        BigDecimal deferredServiceFee = BigDecimal.ZERO;
        if(null != productDeferredInfo){
            deferredInterest = toBeRepaid.multiply(productDeferredInfo.getInterestRate()).multiply(new BigDecimal(productDeferredInfo.getNumDeferredDay()));
            deferredServiceFee = toBeRepaid.multiply(productDeferredInfo.getServiceRate());
        }
        BigDecimal interestAmt = loanIou.getLoanInterest().subtract(loanIou.getRepaidInterest());
        BigDecimal serviceFee = loanIou.getServiceFee().subtract(loanIou.getRepaidServiceFee());
        BigDecimal lateFee = loanIou.getLateFee().subtract(loanIou.getRepaidLateFee());
        BigDecimal minRepay = interestAmt.add(serviceFee).add(lateFee).add(deferredInterest).add(deferredServiceFee);
        log.info("minRepay:{}",minRepay);
        return minRepay;
    }

    /**
     * 检查用户传入的延期id是否有效
     * @param loanIou
     * @param deferredId
     */
    private ProductDeferredInfo checkUserSelectDeferredId(LoanIou loanIou, int deferredId) {
        ProductInfo productInfo = getProductId(loanIou);
        BigDecimal principal = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal());
        ProductDeferredInfo productDeferredInfo = null;
        // 未使用延期包
        try {
            Date repayDate = DateUtils.parseDate(loanIou.getRepayDate(), DateUtils.YYYY_MM_DD_SLASH);
            int periodNum = loanIou.getPeriodNum();
            if (1 == loanIou.getIsDeferred()) {
                // 存在子借据使用了延期包
                repayDate = DateUtils.parseDate(loanIou.getDeferredRepayDate(), DateUtils.YYYY_MM_DD_SLASH);
                //此处是加上了延期的天数
                periodNum = loanIou.getDeferredPeriodNum();
            }
            productDeferredInfo = deferredInfoMapper.selectByIdForCheck(deferredId,
                    principal,
                    DateUtils.parseDateToStr("yyyy-MM-dd 23:59:59",repayDate),
                    periodNum,
                    productInfo.getDeferredMaxDays());
        } catch (ParseException e) {
            log.error("日期转换错误：",e);
            return null;
        }
        return productDeferredInfo;

    }

    /**
     * 根据借据号获取可用延期金融包需支付的最低还款金额(借据列表使用)
     * @param serialNo
     * @return
     */
    public Map<String, Object> getMinRepayBySerialNo(String serialNo){

        List<ProductDeferredInfo> list;
        try {
            list = this.getLoanIouDefferreds(serialNo);
        } catch (ParseException e) {
            log.warn("==获取前端展示的延期金融包数据异常，借据号{}==", serialNo, e);
            return Collections.emptyMap();
        }
        if (Func.isEmpty(list)) {
            log.info("==无可用延期金融包，借据号{}==", serialNo);
            return Collections.emptyMap();
        }

        //获取借据详情
        LoanIou loanIou = getLoanIou(serialNo);
        if (Objects.isNull(loanIou)) {
            log.warn("==查无此借据，借据号{}==", serialNo);
            return Collections.emptyMap();
        }
        ProductDeferredInfo productDeferredInfo = list.get(0);
        BigDecimal minRepay = getMinPay(loanIou, productDeferredInfo);
        String minRepayStr = currency.format(minRepay.setScale(2, BigDecimal.ROUND_HALF_UP));
        Map<String, Object> map = new HashMap<>(2);
        map.put("minRepay", minRepayStr);
        map.put("deferredId", productDeferredInfo.getId());
        return map;
    }
}